JavaScriptã®Symbol.wellKnownããããã£ã®åãåŒãåºããçµã¿èŸŒã¿ã·ã³ãã«ãããã³ã«ã掻çšããŠãªããžã§ã¯ããé«åºŠã«ã«ã¹ã¿ãã€ãºã»å¶åŸ¡ããæ¹æ³ã解説ããŸãã
JavaScript Symbol.wellKnownïŒçµã¿èŸŒã¿ã·ã³ãã«ãããã³ã«ã®åŸ¹åºè§£èª¬
ECMAScript 2015 (ES6)ã§å°å
¥ãããJavaScriptã®Symbolã¯ããªããžã§ã¯ãããããã£ã®ããŒãšããŠé »ç¹ã«äœ¿çšãããããŠããŒã¯ã§äžå€ãªããªããã£ãåã§ããåºæ¬çãªäœ¿ãæ¹ã«å ããSymbolã¯èåãªã·ã³ãã«ïŒwell-known symbolsïŒãšããŠç¥ããããã®ãä»ããŠJavaScriptãªããžã§ã¯ãã®æ¯ãèããã«ã¹ã¿ãã€ãºãã匷åãªã¡ã«ããºã ãæäŸããŸãããããã®ã·ã³ãã«ã¯ãSymbolãªããžã§ã¯ãã®éçããããã£ïŒäŸïŒSymbol.iteratorãSymbol.toStringTagïŒãšããŠå
¬éãããŠããããããããå®çŸ©ãããSymbolå€ã§ãããããã¯JavaScriptãšã³ãžã³ã䜿çšããç¹å®ã®å
éšæäœããããã³ã«ã衚ããŠããŸãããããã®ã·ã³ãã«ãããŒãšããŠããããã£ãå®çŸ©ããããšã§ãJavaScriptã®ããã©ã«ãã®æ¯ãèããååãããªãŒããŒã©ã€ãããããšãã§ããŸãããã®æ©èœã«ãããé«åºŠãªå¶åŸ¡ãšã«ã¹ã¿ãã€ãºãå¯èœã«ãªããããæè»ã§åŒ·åãªJavaScriptã¢ããªã±ãŒã·ã§ã³ãäœæããããšãã§ããŸãã
Symbolãçè§£ãã
èåãªã·ã³ãã«ã«èžã¿èŸŒãåã«ãSymbolèªäœã®åºæ¬ãçè§£ããããšãäžå¯æ¬ ã§ãã
Symbolãšã¯äœãïŒ
Symbolã¯ãŠããŒã¯ã§äžå€ãªããŒã¿åã§ããåSymbolã¯ãããšãåã説æïŒdescriptionïŒã§äœæããããšããŠããç°ãªãããšãä¿èšŒãããŠããŸãããã®ããããã©ã€ããŒãã®ãããªããããã£ãäœæãããããŠããŒã¯ãªèå¥åãšããŠäœ¿çšããã®ã«çæ³çã§ãã
const sym1 = Symbol();
const sym2 = Symbol("description");
const sym3 = Symbol("description");
console.log(sym1 === sym2); // false
console.log(sym2 === sym3); // false
ãªãSymbolã䜿ãã®ãïŒ
- äžææ§ïŒ ããããã£ããŒãäžæã§ããããšãä¿èšŒããåœåã®è¡çªãé²ããŸãã
- ãã©ã€ãã·ãŒïŒ Symbolã¯ããã©ã«ãã§åæå¯èœã§ã¯ãªããããããçšåºŠã®æ å ±é èœãæäŸããŸãïŒãã ããå³å¯ãªæå³ã§ã®çã®ãã©ã€ãã·ãŒã§ã¯ãããŸããïŒã
- æ¡åŒµæ§ïŒ æ¢åã®ããããã£ãšå¹²æžããããšãªããçµã¿èŸŒã¿ã®JavaScriptãªããžã§ã¯ããæ¡åŒµã§ããŸãã
Symbol.wellKnownã®ç޹ä»
Symbol.wellKnownã¯åäžã®ããããã£ã§ã¯ãªããç¹å¥ãªèšèªã¬ãã«ã®ãããã³ã«ã衚ãSymbolãªããžã§ã¯ãã®éçããããã£ã®ç·ç§°ã§ãããããã®ã·ã³ãã«ã¯ãJavaScriptãšã³ãžã³ã®å
éšæäœãžã®ããã¯ãæäŸããŸãã
以äžã«ãæãäžè¬çã«äœ¿çšãããSymbol.wellKnownããããã£ã®ããã€ãã玹ä»ããŸãïŒ
Symbol.iteratorSymbol.toStringTagSymbol.toPrimitiveSymbol.hasInstanceSymbol.species- æååãããã³ã°ã·ã³ãã«ïŒ
Symbol.matchãSymbol.replaceãSymbol.searchãSymbol.split
ç¹å®ã®Symbol.wellKnownããããã£ã®è©³çް
1. Symbol.iteratorïŒãªããžã§ã¯ããå埩å¯èœã«ãã
Symbol.iteratorã·ã³ãã«ã¯ããªããžã§ã¯ãã®ããã©ã«ãã€ãã¬ãŒã¿ãŒãå®çŸ©ããŸãããªããžã§ã¯ããSymbol.iteratorãããŒãšããããããã£ãå®çŸ©ãããã®å€ãã€ãã¬ãŒã¿ãŒãªããžã§ã¯ããè¿ã颿°ã§ããå Žåããã®ãªããžã§ã¯ãã¯å埩å¯èœã§ããã€ãã¬ãŒã¿ãŒãªããžã§ã¯ãã¯ãvalueïŒã·ãŒã±ã³ã¹ã®æ¬¡ã®å€ïŒãšdoneïŒå埩ãå®äºãããã©ããã瀺ãããŒã«å€ïŒã®2ã€ã®ããããã£ãæã€ãªããžã§ã¯ããè¿ãnext()ã¡ãœãããæã€å¿
èŠããããŸãã
䜿çšäŸïŒ ããŒã¿æ§é ã«å¯Ÿããã«ã¹ã¿ã ã®å埩ããžãã¯ãäŸãã°ããªã³ã¯ãªã¹ãã®ãããªã«ã¹ã¿ã ããŒã¿æ§é ãæ§ç¯ããŠãããšããŸããSymbol.iteratorãå®è£
ããããšã§ãfor...ofã«ãŒããã¹ãã¬ããæ§æïŒ...ïŒããã®ä»ã€ãã¬ãŒã¿ãŒã«äŸåããæ§æã§äœ¿çšã§ããããã«ãªããŸãã
äŸïŒ
const myCollection = {
items: [1, 2, 3, 4, 5],
[Symbol.iterator]() {
let index = 0;
return {
next: () => {
if (index < this.items.length) {
return { value: this.items[index++], done: false };
} else {
return { value: undefined, done: true };
}
}
};
}
};
for (const item of myCollection) {
console.log(item);
}
console.log([...myCollection]); // [1, 2, 3, 4, 5]
åœéçãªã¢ãããžãŒïŒ Symbol.iteratorã¯ãã³ã¬ã¯ã·ã§ã³å
ã®èŠçŽ ã«ã¢ã¯ã»ã¹ããããã®ããããã³ã«ããå®çŸ©ãããã®ã ãšèããŠãã ãããããã¯ãç°ãªãæåããè¶ãåºãããã«ç°ãªãç¿æ
£ãæã£ãŠããã®ãšäŒŒãŠããŸããåæåã«ã¯ç¬èªã®ãååŸ©ãæ¹æ³ãããã®ã§ãã
2. Symbol.toStringTagïŒtoString()ã®è¡šçŸãã«ã¹ã¿ãã€ãºãã
Symbol.toStringTagã·ã³ãã«ã¯ããªããžã§ã¯ãã«å¯ŸããŠtoString()ã¡ãœãããåŒã³åºããããšãã«ã¿ã°ãšããŠäœ¿çšãããæååå€ã§ããããã©ã«ãã§ã¯ãObject.prototype.toString.call(myObject)ãåŒã³åºããš[object Object]ãè¿ãããŸããSymbol.toStringTagãå®çŸ©ããããšã§ããã®è¡šçŸãã«ã¹ã¿ãã€ãºã§ããŸãã
䜿çšäŸïŒ ãªããžã§ã¯ãã調æ»ããéã«ããæçãªåºåãæäŸããŸããããã¯ç¹ã«ãããã°ããã®ã³ã°ã«åœ¹ç«ã¡ãã«ã¹ã¿ã ãªããžã§ã¯ãã®åãè¿ éã«ç¹å®ããã®ã«åœ¹ç«ã¡ãŸãã
äŸïŒ
class MyClass {
constructor(name) {
this.name = name;
}
get [Symbol.toStringTag]() {
return 'MyClassInstance';
}
}
const myInstance = new MyClass('Example');
console.log(Object.prototype.toString.call(myInstance)); // [object MyClassInstance]
Symbol.toStringTagããªãå Žåãåºåã¯[object Object]ãšãªããMyClassã®ã€ã³ã¹ã¿ã³ã¹ãåºå¥ããã®ãé£ãããªããŸãã
åœéçãªã¢ãããžãŒïŒ Symbol.toStringTagã¯åœã®æã®ãããªãã®ã§ããæªç¥ã®ãã®ã«ééãããšãã«ãæç¢ºã§ç°¡æœãªèå¥åãæäŸããŸããã人ããšèšãã ãã§ãªããæãèŠãããšã§ãæ¥æ¬ã®äººããšèšãããšãã§ããŸãã
3. Symbol.toPrimitiveïŒå倿ãå¶åŸ¡ãã
Symbol.toPrimitiveã·ã³ãã«ã¯ããªããžã§ã¯ããããªããã£ãå€ã«å€æããããã«åŒã³åºããã颿°å€ã®ããããã£ãæå®ããŸããããã¯ãJavaScriptã+ã==ã®ãããªæŒç®åã䜿çšãããšããã颿°ãããªããã£ãåŒæ°ãæåŸ
ãããšããªã©ããªããžã§ã¯ããããªããã£ãã«å€æããå¿
èŠãããå Žåã«åŒã³åºãããŸãã
䜿çšäŸïŒ ããªããã£ãå€ãå¿ èŠãªã³ã³ããã¹ãã§ãªããžã§ã¯ãã䜿çšãããéã®ãã«ã¹ã¿ã 倿ããžãã¯ãå®çŸ©ããŸããJavaScriptãšã³ãžã³ããæäŸãããããã³ããã«åºã¥ããŠãæåå倿ãŸãã¯æ°å€å€æã®ãããããåªå ãããããšãã§ããŸãã
äŸïŒ
const myObject = {
value: 10,
[Symbol.toPrimitive](hint) {
if (hint === 'number') {
return this.value;
} else if (hint === 'string') {
return `The value is: ${this.value}`;
} else {
return this.value * 2;
}
}
};
console.log(Number(myObject)); // 10
console.log(String(myObject)); // The value is: 10
console.log(myObject + 5); // 15 (default hint is number)
console.log(myObject == 10); // true
const dateLike = {
[Symbol.toPrimitive](hint) {
return hint == "number" ? 10 : "hello!";
}
};
console.log(dateLike + 5);
console.log(dateLike == 10);
åœéçãªã¢ãããžãŒïŒ Symbol.toPrimitiveã¯äžèœç¿»è𳿩ã®ãããªãã®ã§ãããªããžã§ã¯ããã³ã³ããã¹ãã«å¿ããŠç°ãªããèšèªãïŒããªããã£ãåïŒã§ã話ããããšãå¯èœã«ããããŸããŸãªç¶æ³ã§çè§£ãããããšãä¿èšŒããŸãã
4. Symbol.hasInstanceïŒinstanceofã®æ¯ãèããã«ã¹ã¿ãã€ãºãã
Symbol.hasInstanceã·ã³ãã«ã¯ãã³ã³ã¹ãã©ã¯ã¿ãªããžã§ã¯ãããããªããžã§ã¯ãããã®ã³ã³ã¹ãã©ã¯ã¿ã®ã€ã³ã¹ã¿ã³ã¹ãšããŠèªèãããã©ããã倿ããã¡ãœãããæå®ããŸããããã¯instanceofæŒç®åã«ãã£ãŠäœ¿çšãããŸãã
䜿çšäŸïŒ ã«ã¹ã¿ã ã¯ã©ã¹ããªããžã§ã¯ãã«å¯ŸããŠãããã©ã«ãã®instanceofã®æ¯ãèãããªãŒããŒã©ã€ãããŸããããã¯ãæšæºã®ãããã¿ã€ããã§ãŒã³ã®èµ°æ»ãããè€éãŸãã¯åŸ®åŠãªã€ã³ã¹ã¿ã³ã¹ãã§ãã¯ãå¿
èŠãªå Žåã«äŸ¿å©ã§ãã
äŸïŒ
class MyClass {
static [Symbol.hasInstance](obj) {
return !!obj.isMyClassInstance;
}
}
const myInstance = { isMyClassInstance: true };
const notMyInstance = {};
console.log(myInstance instanceof MyClass); // true
console.log(notMyInstance instanceof MyClass); // false
éåžžãinstanceofã¯ãããã¿ã€ããã§ãŒã³ããã§ãã¯ããŸãããã®äŸã§ã¯ãisMyClassInstanceããããã£ã®ååšããã§ãã¯ããããã«ã«ã¹ã¿ãã€ãºããŸããã
åœéçãªã¢ãããžãŒïŒ Symbol.hasInstanceã¯åœå¢ç®¡çã·ã¹ãã ã®ãããªãã®ã§ããããã©ã«ãã®ã«ãŒã«ãäžæžãããç¹å®ã®åºæºã«åºã¥ããŠèª°ããåžæ°ãïŒã¯ã©ã¹ã®ã€ã³ã¹ã¿ã³ã¹ïŒãšèŠãªãããããæ±ºå®ããŸãã
5. Symbol.speciesïŒæŽŸçãªããžã§ã¯ãã®äœæã«åœ±é¿ãäžãã
Symbol.speciesã·ã³ãã«ã¯ã掟çãªããžã§ã¯ããäœæããããã«äœ¿çšãããã¹ãã³ã³ã¹ãã©ã¯ã¿é¢æ°ãæå®ããããã«äœ¿çšãããŸããããã«ããããµãã¯ã©ã¹ã¯èŠªã¯ã©ã¹ã®æ°ããã€ã³ã¹ã¿ã³ã¹ãè¿ãã¡ãœããïŒäŸïŒArray.prototype.sliceãArray.prototype.mapãªã©ïŒã«ãã£ãŠäœ¿çšãããã³ã³ã¹ãã©ã¯ã¿ããªãŒããŒã©ã€ãã§ããŸãã
䜿çšäŸïŒ ç¶æ¿ãããã¡ãœããã«ãã£ãŠè¿ããããªããžã§ã¯ãã®åãå¶åŸ¡ããŸããããã¯ãã«ã¹ã¿ã ã®é
åã©ã€ã¯ãªã¯ã©ã¹ããããsliceã®ãããªã¡ãœãããçµã¿èŸŒã¿ã®Arrayã¯ã©ã¹ã§ã¯ãªããã«ã¹ã¿ã ã¯ã©ã¹ã®ã€ã³ã¹ã¿ã³ã¹ãè¿ãããã«ãããå Žåã«ç¹ã«äŸ¿å©ã§ãã
äŸïŒ
class MyArray extends Array {
static get [Symbol.species]() {
return Array;
}
}
const myArray = new MyArray(1, 2, 3);
const slicedArray = myArray.slice(1);
console.log(slicedArray instanceof MyArray); // false
console.log(slicedArray instanceof Array); // true
class MyArray2 extends Array {
static get [Symbol.species]() {
return MyArray2;
}
}
const myArray2 = new MyArray2(1, 2, 3);
const slicedArray2 = myArray2.slice(1);
console.log(slicedArray2 instanceof MyArray2); // true
console.log(slicedArray2 instanceof Array); // true
Symbol.speciesãæå®ããªãå Žåãsliceã¯Arrayã®ã€ã³ã¹ã¿ã³ã¹ãè¿ããŸããããããªãŒããŒã©ã€ãããããšã§ãMyArrayã®ã€ã³ã¹ã¿ã³ã¹ãè¿ãããããã«ããŸãã
åœéçãªã¢ãããžãŒïŒ Symbol.speciesã¯åºçå°äž»çŸ©ã«ããåœç±ã®ãããªãã®ã§ããåãªããžã§ã¯ããç°ãªããåœç±ãã®èŠªããçãŸãããšããŠããã©ãã®ãåœãïŒã³ã³ã¹ãã©ã¯ã¿ïŒã«å±ããããæ±ºå®ããŸãã
6. æååãããã³ã°ã·ã³ãã«ïŒSymbol.match, Symbol.replace, Symbol.search, Symbol.split
ãããã®ã·ã³ãã«ïŒSymbol.matchãSymbol.replaceãSymbol.searchãããã³Symbol.splitïŒã䜿çšãããšããªããžã§ã¯ãã§æååã¡ãœããã䜿çšããéã®æ¯ãèããã«ã¹ã¿ãã€ãºã§ããŸããéåžžããããã®ã¡ãœããã¯æ£èŠè¡šçŸã«å¯ŸããŠåäœããŸãããªããžã§ã¯ãã«ãããã®ã·ã³ãã«ãå®çŸ©ããããšã§ããããã®æååã¡ãœãããšå
±ã«äœ¿çšããããšãã«ããªããžã§ã¯ããæ£èŠè¡šçŸã®ããã«æ¯ãèãããããšãã§ããŸãã
䜿çšäŸïŒ ã«ã¹ã¿ã ã®æååãããã³ã°ãæäœããžãã¯ãäœæããŸããäŸãã°ãç¹æ®ãªãã¿ãŒã³ã®çš®é¡ã衚ããªããžã§ã¯ããäœæãããããString.prototype.replaceã¡ãœãããšã©ã®ããã«çžäºäœçšããããå®çŸ©ã§ããŸãã
äŸïŒ
const myPattern = {
[Symbol.match](string) {
const index = string.indexOf('custom');
return index >= 0 ? [ 'custom' ] : null;
}
};
console.log('This is a custom string'.match(myPattern)); // [ 'custom' ]
console.log('This is a regular string'.match(myPattern)); // null
const myReplacer = {
[Symbol.replace](string, replacement) {
return string.replace(/custom/g, replacement);
}
};
console.log('This is a custom string'.replace(myReplacer, 'modified')); // This is a modified string
åœéçãªã¢ãããžãŒïŒ ãããã®æååãããã³ã°ã·ã³ãã«ã¯ãç°ãªãèšèªã®ããŒã«ã«ãªç¿»èš³è ã®ãããªãã®ã§ããæååã¡ãœããããæšæºã®æ£èŠè¡šçŸã§ã¯ãªãã«ã¹ã¿ã ã®ãèšèªãããã¿ãŒã³ãçè§£ããæäœã§ããããã«ããŸãã
å®è·µçãªå¿çšãšãã¹ããã©ã¯ãã£ã¹
- ã©ã€ãã©ãªéçºïŒ æ¡åŒµå¯èœã§ã«ã¹ã¿ãã€ãºå¯èœãªã©ã€ãã©ãªãäœæããããã«
Symbol.wellKnownããããã£ã䜿çšããŸãã - ããŒã¿æ§é ïŒ ããŒã¿æ§é ã«ã«ã¹ã¿ã ã€ãã¬ãŒã¿ãŒãå®è£ ããŠãæšæºçãªJavaScriptæ§æã§ããç°¡åã«äœ¿çšã§ããããã«ããŸãã
- ãããã°ïŒ
Symbol.toStringTagãå©çšããŠããããã°åºåã®å¯èªæ§ãåäžãããŸãã - ãã¬ãŒã ã¯ãŒã¯ãšAPIïŒ ãããã®ã·ã³ãã«ã䜿çšããŠãæ¢åã®JavaScriptãã¬ãŒã ã¯ãŒã¯ãAPIãšã®ã·ãŒã ã¬ã¹ãªçµ±åãäœæããŸãã
èæ ®äºé ãšæ³šæç¹
- ãã©ãŠã¶ã®äºææ§ïŒ ã»ãšãã©ã®ã¢ãã³ãã©ãŠã¶ã¯Symbolãš
Symbol.wellKnownããããã£ããµããŒãããŠããŸãããå€ãç°å¢ã®ããã«ã¯é©åãªããªãã£ã«ãçšæããŠãã ããã - è€éãïŒ ãããã®æ©èœãé床ã«äœ¿çšãããšãçè§£ãä¿å®ãå°é£ãªã³ãŒãã«ãªãå¯èœæ§ããããŸããæ éã«äœ¿çšããã«ã¹ã¿ãã€ãºå 容ãååã«ææžåããŠãã ããã
- ã»ãã¥ãªãã£ïŒ Symbolã¯ããçšåºŠã®ãã©ã€ãã·ãŒãæäŸããŸãããå®å šãªã»ãã¥ãªãã£ã¡ã«ããºã ã§ã¯ãããŸãããæå³çãªæ»æè ã¯ããªãã¬ã¯ã·ã§ã³ãä»ããŠSymbolãããŒãšããããããã£ã«ã¢ã¯ã»ã¹ããããšãäŸç¶ãšããŠå¯èœã§ãã
çµè«
Symbol.wellKnownããããã£ã¯ãJavaScriptãªããžã§ã¯ãã®æ¯ãèããã«ã¹ã¿ãã€ãºããèšèªã®å
éšã¡ã«ããºã ãšããæ·±ãçµ±åããããã®åŒ·åãªæ¹æ³ãæäŸããŸãããããã®ã·ã³ãã«ãšãã®äœ¿çšäŸãçè§£ããããšã§ãããæè»ã§æ¡åŒµæ§ãé«ããå
ç¢ãªJavaScriptã¢ããªã±ãŒã·ã§ã³ãäœæã§ããŸãããã ããæœåšçãªè€éããäºææ§ã®åé¡ã念é ã«çœ®ããæ
éã«äœ¿çšããããšãå¿ããªãã§ãã ãããèåãªã·ã³ãã«ã®åãæŽ»çšããŠãJavaScriptã³ãŒãã®æ°ããªå¯èœæ§ãè§£ãæŸã¡ãããã°ã©ãã³ã°ã¹ãã«ã次ã®ã¬ãã«ã«åŒãäžããŸããããåžžã«ãä»ã®äººïŒãããŠæªæ¥ã®èªåïŒãçè§£ãä¿å®ãããããã¯ãªãŒã³ã§ååã«ææžåãããã³ãŒããæžãããåªããŠãã ããããªãŒãã³ãœãŒã¹ãããžã§ã¯ãã«è²¢ç®ããããã³ãã¥ããã£ãšç¥èãå
±æãããããŠãä»ã®äººããããã®é«åºŠãªJavaScriptã®æŠå¿µãåŠã³ãæ©æµãåããããããã«ããããšãæ€èšããŠãã ããã